use matlab_parser::ast::{BinaryOp, Expression, Literal, Program, Statement};
use matlab_parser::parse_matlab_code;
use rstest::rstest;

#[rstest]
#[case("x = 42;", "x", 42.0)]
#[case("y = -10.5;", "y", -10.5)]
fn test_simple_assignment(#[case] code: &str, #[case] var_name: &str, #[case] num_val: f64) {
    let expected = Ok(Program {
        statements: vec![Statement::Assignment {
            left: Expression::Identifier(var_name.to_string()),
            right: if num_val < 0.0 {
                Expression::UnaryOp {
                    op: matlab_parser::ast::UnaryOp::Negate,
                    expr: Box::new(Expression::Literal(Literal::Number(-num_val))),
                }
            } else {
                Expression::Literal(Literal::Number(num_val))
            },
        }],
    });
    assert_eq!(parse_matlab_code(code), expected);
}

#[test]
fn test_function_call_statement() {
    let code = "disp('hello world');";
    let expected = Ok(Program {
        statements: vec![Statement::Expression(Expression::FunctionCall {
            name: "disp".to_string(),
            args: vec![Expression::Literal(Literal::String(
                "hello world".to_string(),
            ))],
        })],
    });
    assert_eq!(parse_matlab_code(code), expected);
}

#[test]
fn test_binary_operation_precedence() {
    let code = "a = 1 + 2 * 3;";
    let expected = Ok(Program {
        statements: vec![Statement::Assignment {
            left: Expression::Identifier("a".to_string()),
            right: Expression::BinaryOp {
                op: BinaryOp::Add,
                left: Box::new(Expression::Literal(Literal::Number(1.0))),
                right: Box::new(Expression::BinaryOp {
                    op: BinaryOp::Mul,
                    left: Box::new(Expression::Literal(Literal::Number(2.0))),
                    right: Box::new(Expression::Literal(Literal::Number(3.0))),
                }),
            },
        }],
    });
    assert_eq!(parse_matlab_code(code), expected);
}

#[test]
fn test_multiple_statements() {
    let code = "x = 5; \n \ty = 10;%11\naa=1";
    let expected = Ok(Program {
        statements: vec![
            Statement::Assignment {
                left: Expression::Identifier("x".to_string()),
                right: Expression::Literal(Literal::Number(5.0)),
            },
            Statement::Assignment {
                left: Expression::Identifier("y".to_string()),
                right: Expression::Literal(Literal::Number(10.0)),
            },
        ],
    });
    let actual=parse_matlab_code(code);
    if let Err(error)=actual.clone(){
        println!("{}",error)
    };
    assert_eq!(actual, expected);
}

#[test]
fn test_parse_error() {
    let code = "x = 5 +;";
    let result = parse_matlab_code(code);
    assert!(result.is_err());
    // You can add more specific assertions about the error message if needed.
    let error_message = result.unwrap_err();
    assert!(error_message.contains("Error: Unexpected token"));
}
